﻿#ifndef SH_BUFFER_BUFFER_HPP
#define SH_BUFFER_BUFFER_HPP

#include "../base.hpp"
#include <cstdint>
#include <string>
#include <vector>
#include <initializer_list>


namespace sh {

class Buffer
{
public:
	// 类型
    using value_type = int8_t;
	using buffer_type = std::vector<value_type>;
	using size_type = buffer_type::size_type;
	using allocator_type = buffer_type::allocator_type;
	using pointer = buffer_type::pointer;
	using const_pointer = buffer_type::const_pointer;
	using reference = value_type&;
	using const_reference = const value_type&;
	using difference_type = buffer_type::difference_type;
	using iterator = buffer_type::iterator;
	using const_iterator = buffer_type::const_iterator;
	using reverse_iterator = buffer_type::reverse_iterator;
	using const_reverse_iterator = buffer_type::const_reverse_iterator;

	static const size_type npos = -1;

	// 构造/复制/销毁
	Buffer() noexcept;
	Buffer(value_type* data, size_type n) : Buffer {(const value_type*)data, n}{}
	Buffer(const value_type* data, size_type n);
	Buffer(size_type n, value_type elem);
	template <class _Iter>
	Buffer(_Iter _First, _Iter _Last);
	Buffer(std::initializer_list<value_type> list);
	Buffer(const Buffer& rhs);
	Buffer(Buffer&& rhs) noexcept;
	Buffer& operator=(Buffer const& rhs);
	Buffer& operator=(Buffer && rhs) noexcept;
	Buffer& operator=(std::initializer_list<value_type> list);
	virtual ~Buffer();



// ----------------------------------------------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------------------------------------------
// -------------------------------------------------------------              -------------------------------------------------------------
// -------------------------------------------------------------    vector    -------------------------------------------------------------
// -------------------------------------------------------------              -------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------------------------------------------------------

	// 赋值
	inline void assign(const_iterator first, const_iterator last) { buffer_.assign(first, last); }
	inline void assign(size_type n, const value_type& u) { buffer_.assign(n, u); }
	inline void assign(std::initializer_list<value_type> list) { buffer_.assign(list); }

    // 迭代器
	inline iterator begin() noexcept { return buffer_.begin(); }
	inline const_iterator begin() const noexcept { return buffer_.begin(); }
	inline iterator end() noexcept { return buffer_.end(); }
	inline const_iterator end() const noexcept { return buffer_.end(); }
	inline reverse_iterator rbegin() noexcept { return buffer_.rbegin(); }
	inline const_reverse_iterator rbegin() const noexcept { return buffer_.rbegin(); }
	inline reverse_iterator rend() noexcept { return buffer_.rend(); }
	inline const_reverse_iterator rend() const noexcept { return buffer_.rend(); }
    inline const_iterator cbegin() const noexcept { return buffer_.cbegin(); }
	inline const_iterator cend() const noexcept { return buffer_.cend(); }
	inline const_reverse_iterator crbegin() const noexcept { return buffer_.crbegin(); }
	inline const_reverse_iterator crend() const noexcept { return buffer_.crend(); }

	// 容量
	inline bool empty() const noexcept { return buffer_.empty(); }
	inline size_type size() const noexcept { return buffer_.size(); }
	inline size_type max_size() const noexcept { return buffer_.max_size(); }
	inline size_type capacity() const noexcept { return buffer_.capacity(); }
	inline void resize(size_type sz) { buffer_.resize(sz); }
	inline void resize(size_type sz, const value_type& c) { buffer_.resize(sz, c); }
	inline void reserve(size_type n) { buffer_.reserve(n); }
	inline void shrink_to_fit() { buffer_.shrink_to_fit(); }

	// 元素访问
	inline reference operator[](size_type n) { return buffer_[n]; }
	inline const_reference operator[](size_type n) const { return buffer_[n]; }
	inline const_reference at(size_type n) const { return buffer_.at(n); }
	inline reference at(size_type n) { return buffer_.at(n); }
	inline reference front() { return buffer_.front(); }
	inline const_reference front() const { return buffer_.front(); }
	inline reference back() { return buffer_.back(); }
	inline const_reference back() const { return buffer_.back(); }

	// 数据访问
	inline value_type* data() noexcept { return buffer_.data(); }
	inline const value_type* data() const noexcept { return buffer_.data(); }

	// 修改器
	template<typename ... Args>
	inline void emplace_back(Args&&... args) { buffer_.emplace_back(std::forward<Args>(args)...); }
	inline void push_back(const_reference val) { buffer_.push_back(val); }
	inline void pop_back() { buffer_.pop_back(); }
	template<typename ... Args> 
	inline iterator emplace(const_iterator position, Args&&... args) { return buffer_.emplace(position, std::forward<Args>(args)...); }
	inline iterator insert(const_iterator position, const_reference x) { return buffer_.insert(position, x); }
    inline iterator insert(const_iterator position, size_type n, const_reference x) { return buffer_.insert(position, n, x); }
	inline iterator insert(const_iterator position, const_iterator first, const_iterator last) { return buffer_.insert(position, first, last); }
	inline iterator insert(const_iterator position, std::initializer_list<value_type> il) { return buffer_.insert(position, il); }
	inline iterator erase(const_iterator position) { return buffer_.erase(position); }
	inline iterator erase(const_iterator first, const_iterator last) { return buffer_.erase(first, last); }
	inline void clear() noexcept { buffer_.clear(); }




	// ----------------------------------------------------------------------------------------------------------------------------------------
	// ----------------------------------------------------------------------------------------------------------------------------------------
	// -------------------------------------------------------------              -------------------------------------------------------------
	// -------------------------------------------------------------     拓展     -------------------------------------------------------------
	// -------------------------------------------------------------              -------------------------------------------------------------
	// ----------------------------------------------------------------------------------------------------------------------------------------
	// ----------------------------------------------------------------------------------------------------------------------------------------


	// 修改器
	void swap(Buffer& buffer);
	void fill(value_type ch);
	void replace(size_type pos, size_type len, Buffer const& buffer);
	void replace(Buffer const& src, Buffer const& dst);
	void insert(size_type index, value_type ch);
	void insert(size_type index, Buffer const& buffer);
	void remove(size_type index);
	void remove(size_type index, size_type n);
	void chop(size_type n); // 删除后n个元素
	void truncate(size_type n); // 保留前n个元素
	void pop_front();
	void append(value_type ch);
	void append(Buffer const& buffer);
	void push_front(value_type ch);
	void push_front(Buffer const& buffer);
	void prepend(value_type ch);
	void prepend(Buffer const& buffer);

	// 分割
	Buffer mid(size_type index, size_type n) const;
	Buffer left(size_type n) const;
	Buffer right(size_type n) const;
	std::vector<Buffer> split(value_type sep) const;

	// 比较 | 统计 | 查找
	bool contains(Buffer const& buffer) const;
	bool startsWith(Buffer const& buffer) const;
	bool endsWith(Buffer const& buffer) const;
	size_type count(value_type ch) const;
	size_type count(Buffer const& buffer) const;
	size_type indexOf(value_type ch, size_type from = 0) const;
	size_type indexOf(Buffer const& buffer, size_type from = 0) const;

	// 转为16进制字符串
	std::string toHex() const;
    std::string toHex(char separator) const;

	// static 
	static Buffer fromHex(std::string const& str); // 从16进制字符串构造

	// operator
	operator buffer_type() { return buffer_; }
	operator const buffer_type() const { return buffer_; }
	Buffer& operator +=(Buffer const& rhs);
	Buffer operator +(Buffer const& rhs);
	bool operator ==(Buffer const& rhs) const;
	bool operator !=(Buffer const& rhs) const;

protected:
	buffer_type buffer_;
};


/*
* //////////////////////////////////////////////////////////////////////////////////////////
*
*
*
* //////////////////////////////////////////////////////////////////////////////////////////
*/


namespace detail {
	static bool _compare_buffer(Buffer::const_iterator l_first, Buffer::const_iterator l_last, Buffer::const_iterator r_first, Buffer::const_iterator r_last) {
		if (l_last - l_first != r_last - r_first) return false;
		while (l_first != l_last) {
			if (*l_first != *r_first) return false;
			l_first++;
			r_first++;
		}
		return true;
	}
} // ns detail

template <class _Iter>
inline 
Buffer::Buffer(_Iter _First, _Iter _Last) : buffer_{_First, _Last} {}

inline
Buffer::Buffer() noexcept
{

}

inline
Buffer::Buffer(const value_type* data, size_type n)
	: buffer_{ data, data + n }
{

}

inline
Buffer::Buffer(size_type n, value_type elem)
	: buffer_(n, elem)
{

}

//inline 
//Buffer::Buffer(const_iterator first, const_iterator last)
//	: buffer_(first, last)
//{
//}

inline
Buffer::Buffer(std::initializer_list<value_type> list)
	: buffer_(list)
{

}

inline
Buffer::Buffer(const Buffer& rhs)
	: buffer_{ rhs.buffer_ }
{

}

inline
Buffer::Buffer(Buffer&& rhs) noexcept
{
	buffer_.swap(rhs.buffer_);
}

inline
Buffer& Buffer::operator=(Buffer const& rhs)
{
	buffer_ = rhs.buffer_;
	return *this;
}

inline
Buffer& Buffer::operator=(Buffer&& rhs) noexcept
{
	buffer_.swap(rhs.buffer_);
	return *this;
}

inline
Buffer& Buffer::operator=(std::initializer_list<value_type> list)
{
	buffer_ = list;
	return *this;
}

inline
Buffer::~Buffer()
{

}





















inline
void Buffer::swap(Buffer& rhs)
{
	buffer_.swap(rhs.buffer_);
}

inline
void Buffer::fill(value_type ch)
{
	std::fill(buffer_.begin(), buffer_.end(), ch);
}

inline
void Buffer::replace(size_type pos, size_type len, Buffer const& buffer)
{
	if (!len || pos + len > size()) return;
	const auto size = buffer.size();
	if (len > size) {
		size_t offset = len - size;
		remove(pos + offset, len - offset);
		len = size;
	}
	memcpy(data() + pos, buffer.data(), len);
	if (len < size) append(buffer.right(size - len));
}

inline
void Buffer::replace(Buffer const& src, Buffer const& dst)
{
	if (src.empty() || src == dst) return;
	do {
		auto index = indexOf(src);
		if (index == npos) break;
		replace(index, src.size(), dst);
	} while (true);
}

inline
void Buffer::insert(size_type index, value_type ch)
{
	if (index > size()) index = size();
	buffer_.insert(buffer_.begin() + index, ch);
}

inline
void Buffer::insert(size_type index, Buffer const& buffer)
{
	if (buffer.empty()) return;
	if (index > size()) index = size();
	auto& inBuffer = buffer.buffer_;
	buffer_.insert(buffer_.begin() + index, inBuffer.begin(), inBuffer.end());
}

inline
void Buffer::remove(size_type index)
{
	if (buffer_.size() <= index) return;
	buffer_.erase(buffer_.begin() + index);
}

inline
void Buffer::remove(size_type index, size_type n)
{
	if (buffer_.size() <= index) return;
	if (buffer_.size() < index + n) n = buffer_.size() - index;
	buffer_.erase(buffer_.begin() + index, buffer_.begin() + index + n);
}

inline
void Buffer::chop(size_type n)
{
	if (!n) return;
	n = n < buffer_.size() ? n : buffer_.size();
	buffer_.erase(buffer_.end() - n, buffer_.end());
}

inline
void Buffer::truncate(size_type n)
{
	if (!n || n >= buffer_.size()) return;
	buffer_.erase(buffer_.begin() + n, buffer_.end());
}

inline
void Buffer::pop_front()
{
	if (!empty()) remove(0);
}

inline
void Buffer::append(value_type ch)
{
	buffer_.push_back(ch);
}

inline
void Buffer::append(Buffer const& buffer)
{
	if (!buffer.size()) return;
	auto& inBuffer = buffer.buffer_;
	buffer_.insert(buffer_.end(), inBuffer.begin(), inBuffer.end());
}

inline
void Buffer::push_front(value_type ch)
{
	insert(0, ch);
}

inline
void Buffer::push_front(Buffer const& buffer)
{
	insert(0, buffer);
}

inline
void Buffer::prepend(value_type ch)
{
	insert(0, ch);
}

inline
void Buffer::prepend(Buffer const& buffer)
{
	insert(0, buffer);
}

inline
Buffer Buffer::mid(size_type index, size_type n) const
{
	if (!n || index + n > size()) return Buffer();
	return Buffer(buffer_.data() + index, n);
}

inline
Buffer Buffer::left(size_type n) const
{
	if (buffer_.size() < n) return *this;
	return Buffer(buffer_.data(), n);
}

inline
Buffer Buffer::right(size_type n) const
{
	if (buffer_.size() < n) return *this;
	return Buffer(buffer_.data() + n, buffer_.size() - n);
}

inline
std::vector<Buffer> Buffer::split(value_type sep) const
{
	if (empty()) return { *this };
	std::vector<Buffer> list;
	const_iterator l = buffer_.begin();
	const_iterator r = l;
	while (r != buffer_.end()) {
		r = std::find(l, buffer_.end(), sep);
		list.emplace_back(Buffer(l, r));
		l = r;
	}
	return list;
}

inline
bool Buffer::contains(Buffer const& buffer) const
{
	//const auto& inBuffer = buffer.buffer_;
	//return std::search(buffer_.begin(), buffer_.end(), inBuffer.cbegin(), inBuffer.cend()) == cend();
	return indexOf(buffer) != npos;
}

inline
bool Buffer::startsWith(Buffer const& buffer) const
{
	if (size() < buffer.size()) return false;
	auto it = cbegin();
	for (auto const& value : buffer)
		if (value != *(it++)) return false;
	return true;
}

inline
bool Buffer::endsWith(Buffer const& buffer) const
{
	if (size() < buffer.size()) return false;
	auto it = cbegin() + size() - buffer.size();
	for (auto const& value : buffer)
		if (value != *(it++)) return false;
	return true;
}

inline
Buffer::size_type Buffer::count(value_type ch) const
{
	size_type n = 0;
	for (auto const& val : buffer_) if (val == ch) ++n;
	return n;
}

inline
Buffer::size_type Buffer::count(Buffer const& buffer) const
{
	if (empty() || buffer.empty()) return 0;
	size_type n = 0, from = 0;
	while (true) {
		from = indexOf(buffer, from);
		if (from == npos) break;
		++from;
		++n;
	}
	return n;
}

inline
Buffer::size_type Buffer::indexOf(value_type ch, size_type from) const
{
	for (size_type i = from; i < buffer_.size(); i++) {
		if (ch == buffer_.at(i)) return i;
	}
	return npos;
}

inline
Buffer::size_type Buffer::indexOf(Buffer const& buffer, size_type from) const
{
	if (from > buffer_.size() || buffer.empty()) return npos;

	size_type n = buffer.size();

	for (auto it = buffer_.cbegin() + from; it < buffer_.cend() - n; ++it) {
		if (detail::_compare_buffer(it, it + n, buffer.cbegin(), buffer.cend())) return it - buffer_.cbegin();
	}

	return npos;
}






inline
std::string Buffer::toHex() const
{
	static const char* HexStr = "0123456789ABCDEF";
	std::string str;
	for (auto const& ch : buffer_) {
		str += HexStr[(uint8_t)ch / 16];
		str += HexStr[(uint8_t)ch % 16];
	}
	return str;
}

inline std::string Buffer::toHex(char separator) const
{
	auto str = toHex();
	if (str.empty() || separator == '\0') return str;
	for (auto it = str.begin(); it != str.end(); ) {
		it++; it++;
		if (it == str.end()) break;
		it = str.insert(it, separator);
		it++;
	}
	return str;
}

inline
Buffer Buffer::fromHex(std::string const& str)
{
	static auto fnGetIndex = [] (char ch) -> int {
		static const char* HexStr = "0123456789ABCDEF";
		for (int i = 0; i < 16; i++) {
			if (HexStr[i] == std::toupper(ch)) return i;
		}
		return -1;
		};

	if (str.empty()) return {};

	size_t i{};
	int index{};
	Buffer buffer;
	if (str.size() % 2) {
		++i;
		index = fnGetIndex(str.at(0));
		if (index < 0) return {};
		buffer.append(index);
	}

	for (; i < str.size(); ) {
		int high = fnGetIndex(str.at(i++));
		int low = fnGetIndex(str.at(i++));
		if (high < 0 || low < 0) return {};
		buffer.append(high << 4 | low);
	}

	return buffer;
}






inline
Buffer& Buffer::operator += (Buffer const& rhs) {
	append(rhs);
	return *this;
}

inline
Buffer Buffer::operator + (Buffer const& rhs)
{
	Buffer buffer = *this;
	buffer.append(rhs);
	return buffer;
}

inline
bool Buffer::operator == (Buffer const& rhs) const
{
	return buffer_ == rhs.buffer_;
}

inline
bool Buffer::operator != (Buffer const& rhs) const
{
	return buffer_ != rhs.buffer_;
}



} // namespace sh






//#ifdef SH_ONLY_HRADER 
//#include "detail/buffer_impl.hpp"
//#endif


#endif // SH_BUFFER_BUFFER_HPP
